/*
 * Пакет "Интерфейс пользователя"
 */
package vitarium.gui;

import vitarium.ecosystem.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.net.URL;
import java.util.Iterator;
import javax.swing.ImageIcon;
import javax.swing.Timer;
import javax.swing.JPanel;

/** Карта для отображения элементов экосистемы*/
public class VitaMap extends JPanel implements ActionListener {

    /** системный таймер */
    Timer timer;
    /** задержка  */
    int delay = 2000;
    private EcoSystem world;
    /** абсолютные координаты для рисования */
    private int x, y;
    /** количество клеток карты (с с Запада на Восток и с Севера на Юг) */
    private int sizeWestToEast, sizeNorthToSouth;
    /** ширина карты на экране ширина карты на экране */
    private int mapScreenWidth;
    /** высота карты на экране */
    private int mapScreenHeight;
    /** долгота выбранной клетки */
    private int currentLocationLongitude;
    /** широта выбранной клетки */
    private int currentLocationLatitude;
    /** Размеры картинок */
    /** высота картинки эдафотопа экосистемы */
    private int elementEdoPicHeight = 64;
    /** высота картинки организма экосистемы */
    private int elementBioPicHeight = 192;
    /** ширина картинки элемента экосистемы  */
    private int elementPicWidth = 128;
    /** ширина картинки цифры в часах */
    private int clockNumberPicWidth = 35;
    /** высота картинки цифры в часах */
    private int clockNumberPicHeight = 48;

    public VitaMap() {
        super();
    }

    /** Создание карты для экосистемы w */
    public VitaMap(EcoSystem w) {
        super();
        this.world = w;

        sizeWestToEast = world.getSizeFromWestToEast();
        sizeNorthToSouth = world.getSizeFromNorthToSouth();

        /** Установка текущей выбранной клетки по умолчанию*/
        currentLocationLongitude = sizeWestToEast / 2;
        currentLocationLatitude = sizeNorthToSouth / 2;
        mapScreenWidth = (elementPicWidth / 2) * (sizeWestToEast + sizeNorthToSouth);
        mapScreenHeight = (elementEdoPicHeight / 2) * (sizeWestToEast + sizeNorthToSouth);

        timer = new Timer(delay, this);
        this.start();
    }

    /** Запуск имитации */
    public void start() {
        timer.start();
    }

    /** Пауза имитации */
    public void pause() {
        timer.stop();
    }

    /** Следующий ход имитации */
    public void next() {
        world.nextTurn();
        this.repaint();
    }

    /** Перерисовка карты */
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        mapScreenWidth = this.getWidth();
        mapScreenHeight = this.getHeight();
        Graphics2D g2d = (Graphics2D) g;

        /* Фон*/
        try {
            Image backgoundLight = new ImageIcon(this.getClass().getResource("/vitarium/resources/gui/back.png")).getImage();
            g.drawImage(backgoundLight, this.centerX() - 400, this.centerY() - 400, null);
        } catch (NullPointerException nullex) {
            // Не обнаружено изображение
        }


        g2d.draw(new Line2D.Float(centerX(), 0, centerX(), mapScreenHeight));
        g2d.draw(new Line2D.Float(0, centerY(), mapScreenWidth, centerY()));


        /** Рисуем эдафотопы */
        for (int i = 0; i < sizeWestToEast; i++) {
            for (int j = 0; j < sizeNorthToSouth; j++) {

                x = (this.centerX() - (elementPicWidth / 2)) - (elementPicWidth / 2) * (currentLocationLongitude) + (elementPicWidth / 2) * (currentLocationLatitude) - (elementPicWidth / 2) * (j) + (elementPicWidth / 2) * (i);
                y = this.centerY() - (elementEdoPicHeight / 2) * (currentLocationLatitude + currentLocationLongitude + 1) + (elementEdoPicHeight / 2) * (i + j);

                if (currentLocationLongitude == i & currentLocationLatitude == j) {
                    try {
                        Image img = new ImageIcon(this.getClass().getResource("/vitarium/resources/terrain/selected.png")).getImage();
                        g.drawImage(img, x, y + 2, null);
                    } catch (NullPointerException nullex) {
                        // Не обнаружено изображение
                    }
                }
                try {
                    g.drawImage(world.getEdaphotope(i, j).getPicture(), x, y, null);
                } catch (NullPointerException nullex) {
                    // Не обнаружено изображение
                }
            }
        }

        /** Рисуем Продуцентов (флора) */
        drawBiocoenosisElements(world.getProducensList().iterator(), g);

        /** Рисуем Консументов 1 порядка (фауна)*/
        drawBiocoenosisElements(world.getPrimaryConsumensList().iterator(), g);

        /** Рисуем Консументов 2 порядка (хищники)*/
        drawBiocoenosisElements(world.getSecondaryConsumensList().iterator(), g);

        /** Элементы управления картой и отображения информации об экосистеме */
        /** Компас */
        try {
            URL imgURL = this.getClass().getResource("/vitarium/resources/gui/compass.png");
            Image compass = new ImageIcon(imgURL).getImage();
            g.drawImage(compass, this.mapScreenWidth - 192, this.mapScreenHeight - 128, null);
        } catch (NullPointerException nullex) {
            // Не обнаружено изображение
        }

        /** Часы */
        drawClock(g);
    }

    /** Отрисовка Часов */
    public void drawClock(Graphics g) {

        /** Расстояние до края*/
        int distanceToBorder = 10;
        // Время существования экосистемы
        int time = this.world.getLivedTime();
        try {
            URL timeUnits = this.getClass().getResource("/vitarium/resources/gui/" + this.getPositionFromNumber(time, 1) + ".png");
            URL timeTens = this.getClass().getResource("/vitarium/resources/gui/" + this.getPositionFromNumber(time, 2) + ".png");

            g.drawImage(new ImageIcon(timeTens).getImage(), distanceToBorder, this.mapScreenHeight - this.clockNumberPicHeight - 10, null);
            g.drawImage(new ImageIcon(timeUnits).getImage(), distanceToBorder + this.clockNumberPicWidth / 10 + this.clockNumberPicWidth, this.mapScreenHeight - this.clockNumberPicHeight - 10, null);
        } catch (NullPointerException nullex) {
            // Не обнаружено изображение
        }
    }

    /** Возвращает нужный разряд из числа */
    public int getPositionFromNumber(int number, int pos) {
        if (pos == 0) {
            return 0;
        }
        int tmp = number;
        for (int i = 1; i < pos; i++) {
            tmp /= 10;
        }
        return tmp % 10;
    }

    /** Отрисовка Организмов из списков */
    public void drawBiocoenosisElements(Iterator it, Graphics g) {
        while (it.hasNext()) {
            BiocoenosisElement be = (BiocoenosisElement) it.next();
            int i = be.getLongitude();
            int j = be.getLatitude();
            x = (this.centerX() - (elementPicWidth / 2)) - (elementPicWidth / 2) * (currentLocationLongitude) + (elementPicWidth / 2) * (currentLocationLatitude) - (elementPicWidth / 2) * (j) + (elementPicWidth / 2) * (i);
            y = this.centerY() - (elementEdoPicHeight / 2) * (currentLocationLatitude + currentLocationLongitude) + (elementEdoPicHeight / 2) * (i + j) - elementBioPicHeight;
            g.drawImage(be.getPicture(), this.x, this.y, null);

        }
    }

    /** Возвращает абциссу центра */
    public int centerX() {
        return mapScreenWidth / 2;
    }

    /** Возвращает ординату центра */
    public int centerY() {
        return mapScreenHeight / 2;
    }

    /** Обработка события - прохождение времени */
    public void actionPerformed(ActionEvent e) {
        this.next();
    }

    /** Изменяет координаты выбранной клетки (перемещается по карте) */
    public void setCurrentLocation(int longitudeChange, int latitudeChange) {
        if (currentLocationLatitude + latitudeChange >= 0 & currentLocationLatitude + latitudeChange < sizeNorthToSouth) {
            currentLocationLatitude += latitudeChange;
        }
        if (currentLocationLongitude + longitudeChange >= 0 & currentLocationLongitude + longitudeChange < sizeWestToEast) {
            currentLocationLongitude += longitudeChange;
        }
        this.repaint();
    }

    /** Возвращает долготу текущей клетки */
    public int getCurrentLocationLongitude() {
        return currentLocationLongitude;
    }

    /** Возвращает широту текущей клетки */
    public int getCurrentLocationLatitude() {
        return currentLocationLatitude;
    }

    /** Изменяет текущую клетку */
    public void changeCurrentLocation(KeyEvent evt) {

        switch (evt.getKeyCode()) {
            case KeyEvent.VK_NUMPAD1:
                this.setCurrentLocation(0, 1);
                break;
            case KeyEvent.VK_NUMPAD2:
            case KeyEvent.VK_DOWN:
                this.setCurrentLocation(1, 1);
                break;
            case KeyEvent.VK_NUMPAD3:
                this.setCurrentLocation(1, 0);
                break;
            case KeyEvent.VK_NUMPAD4:
            case KeyEvent.VK_LEFT:
                this.setCurrentLocation(-1, 1);
                break;
            case KeyEvent.VK_NUMPAD6:
            case KeyEvent.VK_RIGHT:
                this.setCurrentLocation(1, -1);
                break;
            case KeyEvent.VK_NUMPAD7:
                this.setCurrentLocation(-1, 0);
                break;
            case KeyEvent.VK_NUMPAD8:
            case KeyEvent.VK_UP:
                this.setCurrentLocation(-1, -1);
                break;
            case KeyEvent.VK_NUMPAD9:
                this.setCurrentLocation(0, -1);
                break;
        }
    }

    /** Установка заждержки */
    public void setDelay(int newDelay) {
        this.delay = newDelay;
        this.timer.setDelay(delay);
    }

    /** Возвращает заждержку */
    public int getDelay() {
        return this.delay;
    }
}
